package cn.zglbk.network.param.messagedispatcher;
import cn.zglbk.network.param.*;
import cn.zglbk.pb.BytesArray;
import cn.zglbk.utils.SerializableUtils;
import com.google.protobuf.InvalidProtocolBufferException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
@Service
public class DispatchGameMessageService {
    private Logger logger = LoggerFactory.getLogger(DispatchGameMessageService.class);
    private Map<String, DispatcherMapping> dispatcherMappingMap = new HashMap<>();
    /**
     * <p>
     * Description: 服务启动的时候调用此方法，扫描获取此服务要处理的game message类。
     * </p>
     *
     * @param applicationContext
     * @param serviceId          服务id，如果为0,则加载所有的消息类型，如果不为零，则只加载此类型的消息。
     * @author wgs
     * @date 2019年4月27日 下午7:05:11
     */
    public static void scanGameMessages(ApplicationContext applicationContext, int serviceId) {// 构造一个方便的调用方法
        DispatchGameMessageService dispatchGameMessageService = applicationContext.getBean(DispatchGameMessageService.class);
        dispatchGameMessageService.scanGameMessages(serviceId, applicationContext);
    }

    public void scanGameMessages(int serviceId, ApplicationContext applicationContext) {
        Map<String, Object> allGameMessageHandlerClass = applicationContext.getBeansWithAnnotation(GameMessageHandler.class);
        // 遍历获得的所有的Class
        allGameMessageHandlerClass.values().parallelStream().forEach(bean -> {
            GameMessageHandler handler = bean.getClass().getAnnotation(GameMessageHandler.class);
            Method[] methods = bean.getClass().getMethods();
            // 遍历这个类上面的所有方法
            for (Method m : methods) {
                GameMessageMapping gameMessageMapping = m.getAnnotation(GameMessageMapping.class);
                // 判断此方法上面是否有GameMessageMapping
                if (gameMessageMapping != null) {
                    // 从注解中获取处理的IGameMessage对象的Class
                    // 每个服务只加载自己可以处理的消息类型,如果为0则加载所有的类型
                    if (serviceId == 0 || handler.serviceId() == serviceId) {
                        DispatcherMapping dispatcherMapping = new DispatcherMapping(bean, m);
                        this.dispatcherMappingMap.put(handler.proxyId() + "." + gameMessageMapping.messageId(), dispatcherMapping);
                        logger.info("注入{}={}<----||||||||||||||||||||||||---->{}-{}", handler.proxyId(),bean.getClass().getSimpleName(), gameMessageMapping.messageId(),m.getName());
                    }
                }
            }
        });
    }

    /**
     * 当收到网络消息之后，调用此方法。
     *
     * @param gameMessage
     * @param ctx
     */
    public void callMethod(GameMessagePackage gameMessage, IGameChannelContext ctx) {
        // 根据消息的ClassName找到调用方法的信息
        DispatcherMapping dispatcherMapping = this.dispatcherMappingMap.get(gameMessage.getHeader().getServiceId() + "." + gameMessage.getHeader().getMessageId());
        if (dispatcherMapping != null) {
            Object obj = dispatcherMapping.getTargetObj();
            try {
                logger.info("接受到客户端消息，：{}#{}()", obj.getClass().getName(), dispatcherMapping.getTargetMethod().getName());
                Object o = null;
                if (dispatcherMapping.getParam() != null) {
                    o = SerializableUtils.parser(dispatcherMapping.getParam(), gameMessage.getBody());
                }
                Object result = null;
                if (o == null) {
                    result = dispatcherMapping.getTargetMethod().invoke(obj, ctx);
                } else {
                    // 调用处理消息的方法
                    result = dispatcherMapping.getTargetMethod().invoke(obj, o, ctx);
                }
                if (result != null) {
                    BytesArray.BoarException.Builder builder = (BytesArray.BoarException.Builder) result;
                    ctx.sendError(builder);
                }
            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | InvalidProtocolBufferException e) {
                logger.error("调用方法异常，方法所在类：{}，方法名：{}", obj.getClass().getName(), dispatcherMapping.getTargetMethod().getName(), e);
                BytesArray.BoarException.Builder builder = BytesArray.BoarException.newBuilder();
                builder.setCode(-1);
                ctx.sendError(builder);
            }
        } else {
            BytesArray.BoarException.Builder builder = BytesArray.BoarException.newBuilder();
            builder.setCode(-1);
            ctx.sendError(builder);
            logger.warn("消息未找到处理的方法，消息ID：{}--{}", gameMessage.getHeader().getServiceId(), gameMessage.getHeader().getMessageId());
        }
    }

}
